<template>
  <div class="mediaContainer">
    <!-- HTML for user's video -->
    <video class="localVideo" ref="localVideo" autoplay playsinline></video>
    <!-- HTML for remote user's video -->
    <video class="remoteVideo" ref="remoteVideo" autoplay playsinline></video>
    <div class="operation">
      <el-icon :size="size" v-if="constrains.audio" @click="toggleAudio()"><Microphone /></el-icon>
      <el-icon :size="size" v-if="!constrains.audio" @click="toggleAudio()"><Mute /></el-icon>
      <el-icon :size="size" v-if="constrains.video" @click="toggleVideo()"><VideoCamera /></el-icon>
      <el-icon :size="size" v-if="!constrains.video" @click="toggleVideo()"><VideoCameraFilled /></el-icon>
    </div>
  </div>
</template>

<script setup lang="ts">
import {onBeforeUnmount, onMounted, reactive, ref} from "vue";
import {emit, listen, UnlistenFn} from "@tauri-apps/api/event";
import {useUserStore} from "../stores/user.ts";
import {WebviewWindow} from "@tauri-apps/api/webviewWindow";
import {storeToRefs} from "pinia";
import {sendVideoMessage} from "../actions/send_video_message.ts";
import {getCurrentWindow} from "@tauri-apps/api/window";
let {userInfo,toUserAccount} = storeToRefs(useUserStore());
const localVideo = ref(null);
const remoteVideo = ref(null);
let pc:RTCPeerConnection;
let currentStream: MediaStream = reactive({});
let unListenFunc:UnlistenFn = null;
let size = ref(25);
const constrains = reactive({
  video: true,
  audio: true,
});
function listenVideo() {
  return listen("receive-message-video", async (event) => {
    let msg = event.payload;
    console.log("receive-message-video state:", msg.message_type.Video.cmd);
    // 收到对方accept 信息
    if(msg.message_type.Video.cmd === "video_accepted"){
      await sendOffer();
    }
    // 收到对方的offer 信息
    if(msg.message_type.Video.cmd === "video_offer"){
      await handleVideoOfferMsg(msg);
    }
    // 收到对方的answer 信息
    if(msg.message_type.Video.cmd === "video_answer"){
      await handleVideoAnswerMsg(msg);
    }
    // 收到对方的candidate 信息
    if(msg.message_type.Video.cmd === "video_candidate"){
      await handleNewICECandidateMsg(msg);
    }
    // 收到对方的挂断消息
    if(msg.message_type.Video.cmd === "video_hangup"){
      //处理挂断消息,挂断自己的连接
      await hangup();
    }
  });
}


// 初始化本地视频流
async function init(){
  initRTCPeerConnection();

  await navigator.mediaDevices.getUserMedia(constrains)
      .then((stream) => {
        currentStream = stream;
        localVideo.value.srcObject = stream;
        localVideo.value.muted = true;
        currentStream.getTracks().forEach((track) => {
          pc.addTrack(track, currentStream);
        });
      })
      .catch((error) => {
        console.error('Error accessing media devices:', error);
      });
}
function initRTCPeerConnection() {
  const configuration = reactive({
    iceServers: [{
      url: "stun:stun.l.google.com:19302",
    }, {
      url: "turn:numb.viagenie.ca", username: "webrtc@live.com", credential: "muazkh",
    },],
  });
  pc = new RTCPeerConnection(configuration.value);
  // 把自己的视频流信息发送给对方
  pc.onicecandidate = handleICECandidateEvent;
  pc.oniceconnectionstatechange = handleICEConnectionStateChangeEvent;
  pc.onicecandidate = handleICECandidateEvent;
  pc.ontrack = handleTrackEvent;
}
// 处理ice 连接状态改变事件
function handleICEConnectionStateChangeEvent(event: Event) {
  console.log("handleICEConnectionStateChangeEvent:", pc.iceConnectionState,event);
}
// 处理对方发过来的answer
async function handleVideoAnswerMsg(data: any) {
  const decoder = new TextDecoder('utf-8');
  const content: string = decoder.decode(new Uint8Array(data.content));
  const answer = new RTCSessionDescription(JSON.parse(content));
  console.log("5-setRemoteDescription received from remote answer and before set remote answer state:", pc.signalingState);
  await pc.setRemoteDescription(answer);
  console.log("6-setRemoteDescription received from remote answer and after set remote answer state:", pc.signalingState);

}
// 处理对方发过来的offer
async  function handleVideoOfferMsg(data) {
  const decoder = new TextDecoder('utf-8');
  const content: string = decoder.decode(new Uint8Array(data.content));
  const offer = new RTCSessionDescription(JSON.parse(content));
  await pc.setRemoteDescription(offer);
  console.log("3-setRemoteDescription received from remote offer and after set remote offer state:", pc.signalingState);
  let answer:RTCSessionDescriptionInit = await pc.createAnswer();
  await pc.setLocalDescription(answer);
  console.log("4-setLocalDescription after set local  answer state:", pc.signalingState);

  //发送answer 给对方
  let msg = {
    sender_account: userInfo.value.account,
    to_account: toUserAccount.value,
    message_type: {
      cmd: "video_answer",
      method:"all"
    },
    content: pc.localDescription,
  }
  emit("send-message", msg).then(() => {
    console.log("js send-message answer:");
  });
}
// 发送offer 给对方
async function sendOffer(){
  console.log("1-setLocalDescription before set local offer state:", pc.signalingState);
  const offer: RTCSessionDescriptionInit = await pc.createOffer();
  await pc.setLocalDescription(offer);
  let msg = {
    sender_account: userInfo.value.account,
    to_account: toUserAccount.value,
    message_type: {
      cmd: "video_offer",
      method:"all"
    },
    content: pc.localDescription,
  };
  console.log("2-setLocalDescription after set local offer state:", pc.signalingState);
  await emit("send-message", msg).then(() => {
    console.log("js send-message offer successfully");
  });
}
// 处理ice 连接状态改变事件 发送candidate 给对方
function handleICECandidateEvent(event: RTCPeerConnectionIceEvent) {
  console.log("handleICECandidateEvent:", pc.signalingState,event.candidate);
  if (event.candidate && pc.remoteDescription) {
    let msg = {
      sender_account: userInfo.value.account,
      to_account: toUserAccount.value,
      message_type: {
        cmd: "video_candidate",
        method:"all"
      },
      content: event.candidate,
    };
    emit("send-message", msg).then(() => {
      console.log("js send-message candidate:");
    });
  }
}
// 接受对方的candidate
async function handleNewICECandidateMsg(data: any) {
  console.log("handleNewICECandidateMsg:", data.content);
  console.log("handleNewICECandidateMsg state:", pc.signalingState);
  const decoder = new TextDecoder('utf-8');
  const content: string = decoder.decode(new Uint8Array(data.content));
    console.log("handleNewICECandidateMsg content:", content);
  console.log("handleNewICECandidateMsg content:", JSON.parse(content));
  const candidate = new RTCIceCandidate(JSON.parse(content));
  try {
    await pc.addIceCandidate(candidate);
  } catch (err) {
    console.log(err)
  }
}

async function hangup() {
  const window = await WebviewWindow.getByLabel('mediaWebviewWindow')
  pc.close();
  await window.close();
}

// 发送挂断消息给对方,并关闭自己的连接
function onHangup() {
  let msg = {
    sender_account: userInfo.value.account,
    to_account: toUserAccount.value,
    message_type: {
      cmd: "video_hangup",
      method:"all"
    },
    content: "",
  };
  emit("send-message", msg).then(() => {
    console.log("js send-message hangup:");
  }).finally(() => {
    hangup();
  });
}

async function toggleVideo() {
  constrains.video = !constrains.video;
  await updateMediaStream();
}

async function toggleAudio() {
  constrains.audio = !constrains.audio;
  await updateMediaStream();
}
async function updateMediaStream() {
  if (currentStream) {
    currentStream.getTracks().forEach((track) => {
      if (track.kind === 'video' && !constrains.video) {
        track.stop();
      }
      if (track.kind === 'audio' && !constrains.audio) {
        track.stop();
      }
    });
  }
  navigator.mediaDevices.getUserMedia(constrains)
      .then((stream) => {
        currentStream = stream;
        localVideo.value.srcObject = stream;
        localVideo.value.muted = true;
        currentStream.getTracks().forEach((track) => {
          pc.addTrack(track, currentStream);
        });
        sendOffer();
      })
      .catch((error) => {
        console.error('Error accessing media devices:', error);
      });
}
function handleTrackEvent(event: RTCTrackEvent) {
  console.log("handleTrackEvent:", event);
  remoteVideo.value.srcObject = event.streams[0];
}
onMounted(async () => {
  await init();
  await listenVideo().then((unListen) => {
    unListenFunc = unListen;
    const urlParams = new URLSearchParams(window.location.search);
    console.log("urlParams.get(isSender):"+urlParams.get("isSender"));
    if(urlParams.get("isSender") == "true") {
      // 发送视频呼叫消息
      sendVideoMessage("video_call","video_call");
    }else{
      // 发送视频接受消息
      sendVideoMessage("video_accepted","video_accepted");
    }
    console.log("receive-message-video listen success: " + Date.now());
  });
  await getCurrentWindow().once("tauri://close-requested", () => {
    onHangup();
  })
});
onBeforeUnmount(() => {
  if (unListenFunc) {
    unListenFunc();
    console.log("receive-message-video unListen success: " +userInfo.value.account + "->" + toUserAccount.value + Date.now());
  }
  onHangup();
})
</script>

<style scoped>
.mediaContainer {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
  width: 100%;
  flex-direction: column;
  background: linear-gradient(to right, #dcdfe6, #409eff);
  //filter: blur(5px);
}
.localVideo {
  position: absolute;
  width: 30%;
  height: 30%;
  object-fit: cover;
  top: 0;
  right: 0;
}
.remoteVideo {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.operation{
  position: absolute;
  bottom:15px;
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 20px;
}
.operation .el-icon{
  cursor: pointer;
  //border-radius: 30% !important;
  //background-color: #fff !important;
}
.operation .el-icon:hover{
  color: red;
}
</style>